package com.ftg.learn.common.util;

import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 通用处理
 *
 * @author 布衣
 */
public class JwtUtil {

    //钥匙
    public static KeyPair keyPair;

    static {
        try {
            keyPair = KeyPairUtil.generateRSAKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    //过期时间 - 有效时间
    private static final long EXPIRATION_TIME = 3600000;

    public JwtUtil() throws NoSuchAlgorithmException {
    }

    /**
     * 生成JSON Web Token (JWT)
     *
     * @param privateKey 私钥，用于签名JWT，确保令牌的安全性和完整性
     * @param subject    主题，通常用于指定令牌的主体（如用户标识）
     * @return 生成的JWT字符串
     * <p>
     * 此方法创建一个JWT，其中包含关于指定主题的信息它使用提供的私钥进行签名，
     * 以确保令牌在传输过程中未被篡改令牌还设置了过期时间，以防止令牌的长期有效性
     */
    public static String generateJWT(PrivateKey privateKey, String subject) {
        // 获取当前时间戳
        long nowMillis = System.currentTimeMillis();
        // 将时间戳转换为Date对象
        Date now = new Date(nowMillis);
        // 计算令牌过期时间
        Date exp = new Date(nowMillis + EXPIRATION_TIME);

        // 构建JWT
        return Jwts.builder()
                .setSubject(subject) // 设置JWT的主题
                .setIssuedAt(now) // 设置JWT的发行时间
                .setExpiration(exp) // 设置JWT的过期时间
                .signWith(SignatureAlgorithm.RS256, privateKey) // 使用私钥对JWT进行签名
                .compact(); // 将JWT压缩为字符串形式
    }


    /**
     * 生成JSON Web Token (JWT)
     *
     * @param privateKey 私钥，用于签名JWT，确保其安全性
     * @param subject    JWT的声明部分，包含需要传递的信息
     * @return 返回生成的JWT字符串
     */
    public static String generateJWT(PrivateKey privateKey, Map<String, Object> subject) {
        // 获取当前时间戳
        long nowMillis = System.currentTimeMillis();
        // 将时间戳转换为Date对象
        Date now = new Date(nowMillis);
        // 计算JWT的过期时间
        Date exp = new Date(nowMillis + EXPIRATION_TIME);

        // 构建JWT
        return Jwts.builder()
                // 设置JWT的声明部分，包含用户信息或其他数据
                .setClaims(subject)
                // 设置JWT的签发时间
                .setIssuedAt(now)
                // 设置JWT的过期时间
                .setExpiration(exp)
                // 使用私钥对JWT进行签名，确保其安全性
                .signWith(SignatureAlgorithm.RS256, privateKey)
                // 将JWT压缩为字符串并返回
                .compact();
    }

    /**
     * 验证JWT（JSON Web Token）的合法性
     *
     * @param jwt       待验证的JWT字符串
     * @param publicKey 用于验证JWT签名的公钥
     * @return 如果JWT合法且签名未被篡改，则返回true；否则返回false
     */
    public static boolean verifyJWT(String jwt, PublicKey publicKey) {
        try {
            // 使用公钥解析和验证JWT的签名及合法性
            Jwts.parser()
                    .setSigningKey(publicKey)
                    .parseClaimsJws(jwt);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            // 捕获JWT验证过程中可能的异常
            System.out.println("JWT verification failed: " + e.getMessage());
            return false;
        }
    }

    /**
     * 解析JWT（JSON Web Token）并验证其签名的有效性
     * 此方法使用提供的公钥来解析JWT，并返回JWT中的claims（声明）部分
     * 如果JWT的签名无效或解析过程中出现异常，则返回null
     *
     * @param jwt       需要解析和验证的JWT字符串
     * @param publicKey 用于验证JWT签名的公钥
     * @return 包含JWT声明的Map对象，如果解析或验证失败则返回null
     */
    public static Map<String, Object> getClaims(String jwt, PublicKey publicKey) {
        try {
            // 使用提供的公钥解析JWT，并获取JWT的声明部分
            return Jwts.parser()
                    .setSigningKey(publicKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (JwtException | IllegalArgumentException e) {
            // 如果JWT验证失败或解析过程中出现异常，打印错误信息并返回null
            System.out.println("JWT verification failed: " + e.getMessage());
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        // Generate RSA key pair
        KeyPair keyPair = KeyPairUtil.generateRSAKeyPair();
        //存储到了配置文件里面
        String privateKeyPEM = KeyPairUtil.encodeKey(keyPair.getPrivate().getEncoded());
        String publicKeyPEM = KeyPairUtil.encodeKey(keyPair.getPublic().getEncoded());

        //
//        SecretBeanUtil来获取
//        SecretBeanUtil s;
//        s.getPublicKey()


        System.out.println("privateKeyPEM:"+privateKeyPEM);
        System.out.println("publicKeyPEM:"+publicKeyPEM);



        // Generate JWT
        String jwt = generateJWT(keyPair.getPrivate(), "user123");
        System.out.println("Generated JWT: " + jwt);

        Map<String,Object> mmap = getClaims(jwt, keyPair.getPublic());

        // Verify JWT
        boolean isValid = verifyJWT(jwt, keyPair.getPublic());
        System.out.println("JWT is valid: " + isValid);


        System.out.println(JwtUtil.getClaims("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIiwiaWF0IjoxNzUwNDc1NDY4LCJleHAiOjE3NTA0NzkwNjh9.EC7o_E6ZV8jwSt3eDnmE13xNxn2NhdZPa2hr9GL_TqZj6lZ5ppUuewaM8tkD3qrarSwxGZmtNU72zvj7F5tcM6yvlELBd6HXgVyDDCjDfvqUesnjkWB2uoQ4Ji_3j0qtFpG9Md0ta-eY0_Gy8HN95g8smDLT69rE-saq1AF_hPRr4hyFPOlB2L4BlQol-IS2ODRRloDufdMFr2Dp7-_VYy70ERkHYhApGUo2wcIWBDWIME_i6_Z2_AyZQRtIo6lYtIT5jeepI5hI4HeVrtkS_n4fLLKgGOYMeqlMJs2pI9SyWQESD81fERfzkMLjO54xHb4N6pLzmJp1UUwD1UIAYQ", JwtUtil.keyPair.getPublic()));
    }

}
